package p.ithorns.framework.logger;

import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;

/**
 * CommonLogger
 * 必须在日志依赖的地方初始化，否则无法正确输出调用者信息
 *
 * @author ithorns
 * @version 1.0.0
 * @date 2023/3/10 11:40
 */
public class CommonLogger {

    /**
     * 全类名
     */
    private static final String FQCN = CommonLogger.class.getName();

    private volatile boolean enabled;

    private final transient LocationAwareLogger logger;


    private CommonLogger(LocationAwareLogger logger, boolean enabled) {
        synchronized (FQCN) {
            this.logger = logger;
            this.enabled = enabled;
        }
    }


    public static CommonLogger getLogger(boolean enabled) {
        LocationAwareLogger logger = getLocationAwareLogger();
        return new CommonLogger(logger, enabled);
    }

    public synchronized void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    /**
     * Info级别日志
     */
    public void info(String msg, Object... args) {
        if (enabled) {
            logger.log(null, FQCN, LocationAwareLogger.INFO_INT, msg, args, null);
        }
    }

    /**
     * Warn级别日志
     */
    public void warn(String msg, Object... args) {
        if (enabled) {
            logger.log(null, FQCN, LocationAwareLogger.WARN_INT, msg, args, null);
        }
    }

    /**
     * Error级别日志
     */
    public void error(String msg, Object... args) {
        if (enabled) {
            logger.log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, args, null);
        }
    }

    public void error(String msg, Object arg1, Object arg2, Throwable t) {
        if (enabled) {
            logger.log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, new Object[]{arg1, arg2}, t);
        }
    }

    public void error(String msg, Throwable t) {
        if (enabled) {
            logger.log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, new Object[]{}, t);
        }
    }

    /**
     * 获取栈中类信息
     *
     * @return org.slf4j.spi.LocationAwareLogger
     */
    private static LocationAwareLogger getLocationAwareLogger() {
        // 通过堆栈信息获取调用当前方法的类名和方法名
//         JavaLangAccess access = SharedSecrets.getJavaLangAccess();
//         Throwable throwable = new Throwable();
//        // -栈深(下标) 2: 调用者类信息
//         StackTraceElement frame = access.getStackTraceElement(throwable, 2);
//         return (LocationAwareLogger) LoggerFactory.getLogger(frame.getClassName());

        // JDK9+ 通过堆栈信息获取调用当前方法的类名和方法名 RETAIN_CLASS_REFERENCE
        // ！这里栈深是->3
        int stackDepth = 3;
        StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
        StackWalker.StackFrame frame = walker
                .walk(frames -> frames.skip(stackDepth)  .findFirst().orElseThrow(() -> new RuntimeException("No stack frames found")));
        return (LocationAwareLogger) LoggerFactory.getLogger(frame.getClassName());
    }


}